<template>
  <div class="map-container" ref="mapContainer">
    <svg ref="mapSvg" class="china-map"></svg>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, onBeforeUnmount,withDefaults } from "vue";
import * as d3 from "d3";
import chinaJson from "@/api/json/china.json";

const props = withDefaults(defineProps<{
  data?: GeoJsonData;
  hasFlight?: boolean;
  type?: "china" | "province" | "city";
}>(),{type: "china"});
interface GeoJsonFeature {
  type: string;
  properties: {
    name: string;
    [key: string]: any;
  };
  geometry: {
    type: string;
    coordinates: any[];
  };
}

interface GeoJsonData {
  type: string;
  features: GeoJsonFeature[];
}
// 定义份数据类型
type ProvinceName =
  | "广东"
  | "江苏"
  | "浙江"
  | "山东"
  | "安徽"
  | "福建"
  | "江西"
  | "山西"
  | "河北"
  | "河南"
  | "湖北"
  | "湖南"
  | "辽宁"
  | "吉林"
  | "黑龙江"
  | "陕西"
  | "甘肃"
  | "青海"
  | "台湾"
  | "海南"
  | "四川"
  | "贵州"
  | "云南"
  | "北京"
  | "天津"
  | "上海"
  | "重庆"
  | "内蒙古自治区"
  | "广西壮族自治区"
  | "西藏自治区"
  | "宁夏回族自治区"
  | "新疆维吾尔自治区"
  | "香港特别行政区"
  | "澳门特别行政区";
type ProvinceData = Record<ProvinceName, number>;
// 模拟各份数据
const provinceData: ProvinceData = {
  广东: 120,
  江苏: 95,
  浙江: 88,
  山东: 85,
  安徽: 80,
  福建: 78,
  江西: 75,
  山西: 70,
  河北: 65,
  河南: 60,
  湖北: 55,
  湖南: 50,
  辽宁: 45,
  吉林: 40,
  黑龙江: 35,
  陕西: 30,
  甘肃: 25,
  青海: 20,
  台湾: 15,
  海南: 10,
  四川: 95,
  贵州: 70,
  云南: 60,
  北京: 70,
  天津: 50,
  上海: 60,
  重庆: 70,
  内蒙古自治区: 120,
  广西壮族自治区: 50,
  西藏自治区: 90,
  宁夏回族自治区: 60,
  新疆维吾尔自治区: 50,
  香港特别行政区: 70,
  澳门特别行政区: 80,
};

// --有问题的份: 上海 江苏 安徽 福建 山东 西藏 陕西 台湾
const skipProvinces = ["上海", "江苏", "安徽", "福建", "山东", "西藏", "陕西", "台湾"];
// 定义航线数据接口
interface FlightRoute {
  departure: [number, number];
  arrival: [number, number];
  name?: string;
  value?: number;
  path?: [number, number][]; // 新增路径点属性
}
const flightData: FlightRoute[] = [
  {
    departure: [116.4, 39.9],
    arrival: [121.47, 31.23],
    name: "北京-上海",
    path: [
      [116.4, 39.9],
      [117.8, 38.2],
      [119.1, 36.5],
      [120.3, 34.7],
      [121.47, 31.23],
    ],
  },
  {
    departure: [113.26, 23.12],
    arrival: [120.21, 30.24],
    name: "广州-杭州",
    path: [
      [113.26, 23.12],
      [114.7, 24.8],
      [116.3, 26.4],
      [117.9, 27.9],
      [119.2, 29.1],
      [120.21, 30.24],
    ],
  },
  {
    departure: [103.73, 36.03],
    arrival: [114.3, 30.6],
    name: "兰州-武汉",
    path: [
      [103.73, 36.03],
      [105.8, 35.2],
      [107.9, 34.3],
      [110.0, 33.2],
      [112.1, 32.0],
      [114.3, 30.6],
    ],
  },
  {
    departure: [104.06, 30.67],
    arrival: [117.28, 31.86],
    name: "成都-合肥",
    path: [
      [104.06, 30.67],
      [106.5, 31.2],
      [109.0, 31.5],
      [111.5, 31.8],
      [114.0, 31.9],
      [117.28, 31.86],
    ],
  },
  {
    departure: [126.53, 45.8],
    arrival: [108.94, 34.26],
    name: "哈尔滨-西安",
    path: [
      [126.53, 45.8],
      [123.0, 43.5],
      [119.5, 41.0],
      [116.0, 38.5],
      [112.5, 36.3],
      [108.94, 34.26],
    ],
  },
];
// 使用时添加类型保护
const getProvinceValue = (name: string): number => {
  return name in provinceData ? provinceData[name as ProvinceName] : 0;
};

const mapContainer = ref<HTMLElement>(); // 父容器引用
const mapSvg = ref<SVGSVGElement | null>(null);
const mapWidth = ref<number>(0);
const mapHeight = ref<number>(0);
//  const MARGIN = { top: 20, right: 10, bottom: 30, left: 30 };

let resizeObserver: ResizeObserver;
onMounted(() => {
  if (mapContainer.value) {
    const { width, height } = mapContainer.value.getBoundingClientRect();
    console.log("元素宽高:", width, height);
    mapWidth.value = width;
    mapHeight.value = height;
    initResizeObserver();
    // drawAllMap(width, height);
    //  drawSingleProvince("十段线");
  }
});
// 在组件卸载时移除工具提示
onBeforeUnmount(() => {
  resizeObserver?.disconnect();
});
onBeforeUnmount(() => {
  resizeObserver?.disconnect();
}); 
// 初始化尺寸观察
const initResizeObserver = () => {
  console.log("initResizeObserver",props.type);
  if (!mapContainer.value) return;

  resizeObserver = new ResizeObserver((entries) => {
    const entry = entries[0];
    if (!entry) return;
   let { width } = entry.contentRect;
    // 计算高度，不超过视口的75%
    let height = Math.min(entry.contentRect.height, window.innerHeight * 0.75);
    mapWidth.value = width;
    mapHeight.value = height;
    if (props.type == "china") {
      drawAllMap(width, height); // 尺寸变化时重绘地图
    }else  {
      drawSingleProvince("广东");
    }
  });

  resizeObserver.observe(mapContainer.value);
};
const drawAllMap = (width = 800, height = 600) => {
  console.log(width, height);
  if (!mapSvg.value) return;
  if (!mapContainer.value) return;
  const svg = d3
    .select(mapSvg.value)
    .html("")
    .attr("width", width)
    .attr("height", height); // 移除所有子元素

  // 创建颜色比例尺
  const colorScale = d3
    .scaleSequential((t) => `rgba(100, 150, 255, ${0.3 + t * 0.7})`)
    .domain([0, d3.max(Object.values(provinceData)) || 100]);

  const scale = width / height;
  console.log(scale);
  // 创建投影
  const projection = d3
    .geoMercator()
    .center([104.0, 37.5])
    .scale(Math.min(width, height * 1.3) * 0.8)
    .translate([width / 2, height / 2]);
  const safeProjection = (p: [number, number]): [number, number] => {
    if (!projection) return [0, 0];
    const projected = projection(p);
    return projected ? projected : [0, 0];
  };
  const path = d3.geoPath().projection(projection);

  // 创建工具提示
  const tooltip = d3
    .select(mapContainer.value)
    .append("div")
    .attr("class", "map-tooltip")
    .style("opacity", 0)
    .style("position", "absolute")
    .style("background", "#ccc")
    .style("padding", "8px")
    .style("border-radius", "4px")
    .style("box-shadow", "0 2px 6px rgba(0,0,0,0.83)")
    .style("pointer-events", "none")
    .style("font-family", "sans-serif")
    .style("font-size", "14px");

  let provinces = (chinaJson as GeoJsonData).features.filter(
    (f) => !skipProvinces.includes(f.properties.name)
  );
  // 绘制地图
  svg
    .append("g")
    .selectAll("path")
    .data(provinces)
    .enter()
    .append("path")
    .attr("d", path as any)
    .attr("fill", (d: any) => {
      const value = getProvinceValue(d.properties.name) || 30;
      return colorScale(value) as string;
    })
    .attr("stroke", "#a8d2fa")
    .attr("stroke-width", 1)
    .attr("class", "province")
    .on("mouseover", function (event: MouseEvent, d: GeoJsonFeature) {
      d3.select(this).attr("fill", "rgba(0, 128, 255, 0.192)");

      const value = getProvinceValue(d.properties.name) || 0;
      tooltip.transition().duration(200).style("opacity", 0.9);
      tooltip
        .html(
          `
        <div><strong>${d.properties.name}</strong></div>
        <div>数值: ${value}</div>
      `
        )
        .style("left", `${event.pageX + 10}px`)
        .style("top", `${event.pageY - 28}px`);
    })
    .on("mouseout", function (event: MouseEvent, d: GeoJsonFeature) {
      const value = getProvinceValue(d.properties.name);
      d3.select(this).attr("fill", colorScale(value) as string);
      tooltip.transition().duration(500).style("opacity", 0);
    });

  const defs = svg.append("defs");
  defs
    .append("linearGradient")
    .attr("id", "line-gradient")
    .attr("gradientUnits", "userSpaceOnUse")
    .selectAll("stop")
    .data([
      { offset: "0%", color: "rgba(100, 200, 255, 0.2)" },
      { offset: "50%", color: "rgba(100, 200, 255, 0.8)" },
      { offset: "100%", color: "rgba(100, 200, 255, 0.2)" },
    ])
    .enter()
    .append("stop")
    .attr("offset", (d) => d.offset)
    .attr("stop-color", (d) => d.color);

  // 绘制航线
  renderRoutes(svg, path, safeProjection, projection);

  // 添加缩放功能
  return;
  const zoom = d3
    .zoom()
    .scaleExtent([1, 8])
    .on("zoom", (event) => {
      svg.selectAll("path").attr("transform", event.transform);
      svg.selectAll("text").attr("transform", event.transform);
    });

  svg.call(zoom as any);
};
// 绘制航线
const renderRoutes = (svg: any, _path: any, safeProjection: any, _projection: any) => {
  const routeGroup = svg.append("g").attr("class", "routes");
  renderMapPoints(svg, routeGroup, safeProjection);

  // 绘制航线（高光线）
  const routeHighlights = svg
    .append("g")
    .selectAll(".route-highlight")
    .data(flightData)
    .enter()
    .append("path")
    .attr("class", "route-highlight")
    .attr("d", (d: any) => {
      const start = safeProjection(d.departure);
      const end = safeProjection(d.arrival);

      // 计算控制点（向上偏移形成弧度）
      const controlHeight = 30; // 弧度高度，可调整
      const controlX = (start[0] + end[0]) / 2;
      const controlY = (start[1] + end[1]) / 2 - controlHeight;

      // 二次贝塞尔曲线
      return `M${start[0]},${start[1]} Q${controlX},${controlY} ${end[0]},${end[1]}`;
    })
    .attr("fill", "none")
    .attr("stroke", "#fff") // 细线颜色
    .attr("stroke-width", 1) // 细线宽度
    .attr("stroke-opacity", 1);

  // 创建飞机图标组
  const airplanes = svg
    .append("g")
    .selectAll(".airplane")
    .data(flightData)
    .enter()
    .append("g")
    .attr("class", "airplane");

  // 添加飞机图标（SVG路径）
  airplanes
    .append("path")
    .attr("d", "M -12,0 L -8,-4 L 10,0 L -8,4 Z") // 飞机形状  M-8,0 L0,-5 L8,0 L0,5 Z
    .attr("fill", "#ff5252")
    .attr("stroke", "#fff")
    .attr("stroke-width", 1);

  // 飞机尾翼（可选）
  airplanes
    .append("path")
    .attr("d", "M -6,-4 L -6,-6 L 2,-6 L 2,-4 Z") // 左侧尾翼
    .attr("fill", "#ff5252")
    .attr("stroke", "#fff")
    .attr("stroke-width", 0.8);

  airplanes
    .append("path")
    .attr("d", "M -6,4 L -6,6 L 2,6 L 2,4 Z") // 右侧尾翼
    .attr("fill", "#ff5252")
    .attr("stroke", "#fff")
    .attr("stroke-width", 0.8);

  // 动画函数
  function animateFlights() {
    // 飞机动画
    airplanes
      .transition()
      .duration(8000) // 8秒完成一次飞行
      .attrTween("transform", function (d: any) {
        const start = safeProjection(d.departure);
        const end = safeProjection(d.arrival);
        const controlX = (start[0] + end[0]) / 2;
        const controlY = (start[1] + end[1]) / 2 - 30;

        const tempPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
        tempPath.setAttribute(
          "d",
          `M${start[0]},${start[1]} Q${controlX},${controlY} ${end[0]},${end[1]}`
        );

        return function (t: any) {
          const length = tempPath.getTotalLength();
          const currentPos = t * length;
          const point = tempPath.getPointAtLength(currentPos);

          // 计算角度（向前看5像素）
          const lookAhead = Math.min(currentPos + 5, length);
          const nextPoint = tempPath.getPointAtLength(lookAhead);

          // 计算角度并微调
          let angle =
            (Math.atan2(nextPoint.y - point.y, nextPoint.x - point.x) * 180) / Math.PI;

          // 调整飞机位置偏移量（这里可以根据需要调整）
          const offsetX = 0; // X轴偏移量
          const offsetY = 0; // Y轴偏移量

          return `translate(${point.x + offsetX},${point.y + offsetY}) rotate(${angle})`;
        };
      })
      .on("start", function (_d: any, i: any) {
        // 飞机起飞时显示高光线
        routeHighlights
          .filter((_d: any, j: any) => j === i)
          .transition()
          .style("opacity", 1);
      })
      .on("end", function (this: any, d: any, i: any) {
        // 飞机到达时隐藏高光线
        routeHighlights
          .filter((_: any, j: any) => j === i)
          .transition()
          .style("opacity", 0);

        // 重新开始动画
        d3.select(this)
          .attr(
            "transform",
            `translate(${safeProjection(d.departure)[0]},${
              safeProjection(d.departure)[1]
            })`
          )
          .transition()
          .delay(1000) // 1秒延迟后重新起飞
          .call(animateFlights);
      });
  }
  // 开始动画
  animateFlights();
};
// --绘制起终点圆点
const renderMapPoints = (svg: any, routeGroup: any, safeProjection: any) => {
  // 2. 绘制起点文本
  routeGroup
    .selectAll(".route-start-label")
    .data(flightData)
    .enter()
    .append("text")
    .attr("class", "route-start-label")
    .attr("x", (d: any) => safeProjection(d.departure)[0])
    .attr("y", (d: any) => safeProjection(d.departure)[1] - 10)
    .text((d: any) => d.name?.split("-")[0] || "")
    .attr("fill", "white");

  // 3. 绘制终点文本
  routeGroup
    .selectAll(".route-end-label")
    .data(flightData)
    .enter()
    .append("text")
    .attr("class", "route-end-label")
    .attr("x", (d: any) => safeProjection(d.arrival)[0])
    .attr("y", (d: any) => safeProjection(d.arrival)[1] - 10)
    .text((d: any) => d.name?.split("-")[1] || "")
    .attr("fill", "white");
  // 合并绘制起点和终点
  const pointGroups = svg
    .append("g")
    .selectAll(".point-group")
    .data([
      ...flightData.map((d) => ({ ...d, type: "departure" })),
      ...flightData.map((d) => ({ ...d, type: "arrival" })),
    ])
    .enter()
    .append("g")
    .attr("class", (d: any) => `point-group ${d.type}-point-group`)
    .attr("transform", (d: any) => {
      const [x, y] = safeProjection(d.type === "departure" ? d.departure : d.arrival);
      return `translate(${x},${y})`;
    });

  // 绘制外环（两个圆环中较大的一个）
  pointGroups
    .append("circle")
    .attr("class", (d: any) => `${d.type}-outer-ring`)
    .attr("r", 12)
    .attr("fill", "none")
    .attr("stroke", (d: any) => (d.type === "departure" ? "#ff5252" : "#4dabf7")) // 起点红色，终点蓝色
    .attr("stroke-width", 1.5)
    .attr("stroke-opacity", 0.6);

  // 绘制内环（两个圆环中较小的一个）
  pointGroups
    .append("circle")
    .attr("class", (d: any) => `${d.type}-inner-ring`)
    .attr("r", 8)
    .attr("fill", "none")
    .attr("stroke", (d: any) => (d.type === "departure" ? "#ff5252" : "#4dabf7"))
    .attr("stroke-width", 1.5)
    .attr("stroke-opacity", 0.8);

  // 绘制中心圆点
  pointGroups
    .append("circle")
    .attr("class", (d: any) => `${d.type}-point`)
    .attr("r", 5)
    .attr("fill", (d: any) => (d.type === "departure" ? "#ff5252" : "#4dabf7"))
    .attr("stroke", "#fff")
    .attr("stroke-width", 1.5);
};

// 在 setup 函数或 onMounted 中
const drawSingleProvince = (provinceName: string) => {
  if (!mapSvg.value) return;

  // 清空现有内容
  d3.select(mapSvg.value).selectAll("*").remove();

  const width = 800;
  const height = 600;

  const svg = d3.select(mapSvg.value).attr("width", width).attr("height", height);

  // 查找目标份
  const provinces = (chinaJson as GeoJsonData).features.find((f) => {
    console.log(f, f.properties.name);
    return f.properties.name === provinceName;
  });

  if (!provinces) {
    console.error(`未找到份: ${provinces}`);
    return;
  }

  // 创建投影 - 针对单个份调整
  // @ts-ignore
  const projection = d3
    .geoMercator()
    .center([104.0, 37.5]) // 中心点坐标
    .scale(300) // 调整这个数值可以改变地图大小
    .translate([width / 2, height / 2]);

  const path = d3.geoPath().projection(projection);

  // 绘制单个份
  svg
    .append("path")
    .datum(provinceData)
    .attr("d", path as any)
    .attr("fill", "#69b3a2")
    .attr("stroke", "#fff")
    .attr("stroke-width", 1);

  // 添加份名称
  svg
    .append("text")
    .attr("x", width / 2)
    .attr("y", 30)
    .attr("text-anchor", "middle")
    .attr("font-size", "20px")
    .text(provinceName);
};
</script>

<style scoped>
.map-container {
  width: 100%;
  display: flex;height: 100%;
  max-height: 80vh;
  justify-content: center;overflow: hidden;
}

.china-map {
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 8px; max-height: inherit; /* 继承容器的最大高度限制 */
  object-fit: contain; /* 保持比例同时适应容器 */
}

.province:hover {
  opacity: 0.8;
  cursor: pointer;
}
.airplane {
  transition: transform 0.1s linear;
}

.route {
  stroke: rgba(100, 200, 255, 0.3);
  stroke-width: 2;
  fill: none;
}

.route-highlight {
  stroke: url(#line-gradient);
  stroke-width: 3;
  fill: none;
}
.route-path {
  stroke-width: 1.5;
  opacity: 0.8;
  fill: none;
}

.route-start-label,
.route-end-label {
  font-size: 12px;
  font-weight: bold;
  fill: #333;
  text-anchor: middle;
  pointer-events: none;
  text-shadow: 0 0 2px white; /* 提高可读性 */
}
.departure-point {
  fill: #ff5252;
  stroke: white;
  stroke-width: 1.5px;
}

.arrival-point {
  fill: #4dabf7;
  stroke: white;
  stroke-width: 1.5px;
}
</style>

<style>
/* 全局工具提示样式 */
.map-tooltip {
  z-index: 1000;
}
</style>
